package org.koin.hos.ext.hos;

import ohos.app.Context;
import org.koin.core.Koin;
import org.koin.core.component.KoinComponent;
import org.koin.core.component.KoinScopeComponent;
import org.koin.core.context.GlobalContext;
import org.koin.core.error.*;
import org.koin.core.parameter.ParametersDefinition;
import org.koin.core.qualifier.Qualifier;
import org.koin.core.qualifier.TypeQualifier;
import org.koin.core.scope.Scope;
import org.koin.hos.scope.HosScopeComponent;

public class ContextExt {

    /**
     * Get Koin context
     */
    public static Koin getKoin(Context context) {
        if (context instanceof KoinComponent) {
            return ((KoinComponent) context).getKoin();
        } else {
            return GlobalContext.INSTANCE().get();
        }
    }

    public static Scope getDefaultScope(Context context) {
        if (context instanceof HosScopeComponent) {
            return ((HosScopeComponent) context).getScope();
        } else if (context instanceof KoinScopeComponent) {
            return ((KoinScopeComponent) context).getScope();
        } else {
            return getKoin(context).getRootScope();
        }
    }

    /**
     * get given dependency for Hos koincomponent
     *
     * @param context
     * @param clazz
     * @param qualifier
     * @param parameters - injection parameters
     */
    public static <T> T get(Context context,
                            Class clazz,
                            Qualifier qualifier,
                            ParametersDefinition parameters) {
        try {
            return getDefaultScope(context).get(clazz, qualifier, parameters);
        } catch (ClosedScopeException e) {
            e.printStackTrace();
        } catch (DefinitionParameterException e) {
            e.printStackTrace();
        } catch (NoBeanDefFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T get(Context context,
                            Class clazz) {

        return get(context, clazz, null, null);
    }

    public static <T> T get(Context context,
                            Class clazz,
                            Qualifier qualifier) {

        return get(context, clazz, qualifier, null);
    }

    public static <T> T get(Context context,
                            Class clazz,
                            ParametersDefinition parameters) {

        return get(context, clazz, null, parameters);
    }

    /**
     * get given dependency for Hos koincomponent
     *
     * @param context
     * @param clazz
     * @param qualifier
     * @param parameters - injection parameters
     */
    public static <T> T inject(Context context,
                               Class clazz,
                               Qualifier qualifier,
                               ParametersDefinition parameters) {

        return get(context, clazz, qualifier, parameters);
    }

    public static <T> T inject(Context context,
                               Class clazz) {

        return get(context, clazz, null, null);
    }

    public static <T> T inject(Context context,
                               Class clazz,
                               Qualifier qualifier) {

        return get(context, clazz, qualifier, null);
    }

    public static <T> T inject(Context context,
                               Class clazz,
                               ParametersDefinition parameters) {

        return get(context, clazz, null, parameters);
    }

    /**
     * get given dependency for Hos koincomponent, from primary and secondary types
     *
     * @param parameters - injection parameters
     */
    public static <S, P> S bind(Context context,
                                Class<S> sClass,
                                Class<P> pClass,
                                ParametersDefinition parameters) {
        try {
            return getKoin(context).bind(sClass, pClass, parameters);
        } catch (NoBeanDefFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Scope createScope(Context context,
                                    Object source) {

        String scopeId = KoinScopeComponent.getScopeId(context);
        TypeQualifier scopeName = KoinScopeComponent.getScopeName(context);
        try {
            return getKoin(context).createScope(scopeId, scopeName, source);
        } catch (ScopeAlreadyCreatedException e) {
            e.printStackTrace();
        } catch (NoScopeDefFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Scope createScope(Context context) {
        return createScope(context, null);
    }

    public static Scope getScopeOrNull(Context context) {
        String scopeId = KoinScopeComponent.getScopeId(context);
        return getKoin(context).getScopeOrNull(scopeId);
    }

    public static Scope newScope(Context context) {
        return createScope(context);
    }

    public static Scope getOrCreateScope(Context context) {
        Scope scope = getScopeOrNull(context);
        if (scope == null) {
            scope = createScope(context);
        }
        return scope;
    }
}
